/**
 * @file tiny_thread.c
 * @brief 线程管理
 * @author 张恒宣 
 * @LastEditTime 2025/4/06
 * 
 * MIT License
 *
 * Copyright (c) 2025 张恒宣 luckkeymail@163.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */


/*********************
 *      头文件
 *********************/

#include "tiny_thread.h"
#include "tiny_malloc.h"
#include "tiny_rtos_context.h"

/*********************
 *   用于管理各个线程
 *   状态的变量
 *********************/
 
extern tiny_list_t thread_all_list;
extern tiny_list_t thread_exit_list;
extern tiny_list_t thread_suspend_list;
extern tiny_list_t thread_ready_list[TINY_THREAD_MAX_PRIORITY];
extern tiny_thread_t *cur_running_thread;

tiny_list_t thread_all_list;
tiny_list_t thread_exit_list;
tiny_list_t thread_suspend_list;
tiny_list_t thread_ready_list[TINY_THREAD_MAX_PRIORITY];
tiny_thread_t *cur_running_thread;
tiny_uint32_t all_runtime = 1.0f;
/*********************
 *     私有函数
 *********************/

static void tiny_thread_exit(void *param)
{
	UNUSED_PARAMETER(param);
	tiny_kill_thread(cur_running_thread);
}

static void tiny_thread_timeout(void *param)
{
	int flag = disable_interrupt();
	tiny_thread_t *tthread = param;
	tthread->statu = THREAD_READY;
	tthread->timer_ret = THREAD_BLOCK_TIMEOUT;
	tiny_remove_node_from_list(&tthread->list_node_link);
	tiny_list_insert_pre(&thread_ready_list[tthread->cur_priority], &tthread->list_node_link);
	enable_interrupt(flag);
}

/// @brief 初始化线程栈
/// @param sp 栈指针
/// @param stack_size 栈大小
/// @param entry_callback 线程函数地址
/// @param param 函数参数
/// @param exit_callback 线程退出后返回的函数地址
/// @return
static tiny_uint8_t * __attribute__((optnone, noinline)) tiny_init_thread_stack(tiny_uint32_t *sp, tiny_uint32_t stack_size, thread_callback_t entry_callback, tiny_uint32_t *param, thread_callback_t exit_callback)
{
	tiny_uint8_t *stack = (tiny_uint8_t *)tiny_malloc(stack_size);
	if (!stack)
	{
		return tiny_null;
	}
#if IS_OPEN_STACK_HIGH_WATER == PROFILE_OPEN
	tiny_memset(stack, STACK_HIGH_WATER_FILL, stack_size);
#endif
	
	*sp = ((tiny_uint32_t)stack + stack_size - sizeof(tiny_tcb_t));
	tiny_tcb_t *tcb = (tiny_tcb_t *)(*sp);

	tcb->r4 = 0;
	tcb->r5 = 0;
	tcb->r6 = 0;
	tcb->r7 = 0;
	tcb->r8 = 0;
	tcb->r9 = 0;
	tcb->r10 = 0;
	tcb->r11 = 0;

	tcb->env_reg.r0 = (tiny_uint32_t)param;
	tcb->env_reg.r1 = 0;
	tcb->env_reg.r2 = 0;
	tcb->env_reg.r3 = 0;
	tcb->env_reg.r12 = 0;
	tcb->env_reg.lr = (tiny_uint32_t)exit_callback;
	tcb->env_reg.pc = (tiny_uint32_t)entry_callback;
	tcb->env_reg.xpsr = 0x01000000L;

	return stack;
}


/*********************
 *      公共函数
 *********************/

/// @brief 创建线程
/// @param name 线程名字
/// @param stack_size 栈大小
/// @param priority 优先级
/// @param entry_callback 函数回调
/// @param param 函数回调参数
/// @return 线程句柄, 如果失败反回tiny_null
tiny_thread_hander tiny_thread_create(const char *name, tiny_uint32_t stack_size, tiny_uint32_t priority, thread_callback_t entry_callback, void *param)
{
	static tiny_uint32_t cur_tid = 0;
	tiny_thread_t *tthread = (tiny_thread_t *)tiny_malloc(sizeof(tiny_thread_t));
	if (tthread == tiny_null)
	{
		return tiny_null;
	}
	tthread->name = name;
	tthread->init_priority = (priority > (TINY_THREAD_MAX_PRIORITY - 1)) ? (TINY_THREAD_MAX_PRIORITY - 1) : priority;
	tthread->cur_priority = tthread->init_priority;

	tthread->init_tick = TINY_THREAD_INIT_TICK;
	tthread->remain_tick = TINY_THREAD_INIT_TICK;
	tthread->statu = THREAD_SUSPEND;
	tthread->statck_size = ALIGN(stack_size);
	tthread->timer_ret = THREAD_BLOCK_NOT_TIMEOUT;
	tthread->exit_hook = tiny_null;
	tthread->exit_hook_param = tiny_null;
	tthread->min_remain_stack = 0;
	
	int flag = disable_interrupt();
	tthread->tid = cur_tid++;
	enable_interrupt(flag);
	
#if IS_OPEN_GET_CPU == PROFILE_OPEN
	tthread->schedule_last_tick = 0;
	tthread->run_time = 0;
	tthread->cpu_usage = 0.0f;
#endif
	
	tiny_init_list_node(&tthread->list_node_link);
	
	tiny_init_list_node(&tthread->list_all_thread_link);
	tiny_list_insert_pre(&thread_all_list, &tthread->list_all_thread_link); 
	
	tiny_timer_obj_init(&tthread->timer, TIMER_OWNER_THREAD, TIMER_ONCE, 0, tiny_thread_timeout, tthread);
	
	tthread->stack = tiny_init_thread_stack(&tthread->sp, tthread->statck_size, entry_callback, param, tiny_thread_exit);
	if (!tthread->stack)
	{
		tiny_free(tthread);
		return tiny_null;
	}
	return tthread;
}

/// @brief 将线程添加到就绪链表
/// @param thread 线程句柄
void tiny_thread_startup(tiny_thread_hander thread)
{
	if (!thread)
	{
		return;
	}

	int flag = disable_interrupt();
	tiny_thread_t *tthread = thread;
	tthread->statu = THREAD_READY;
	tiny_list_insert_pre(&thread_ready_list[tthread->cur_priority], &tthread->list_node_link); 

	enable_interrupt(flag);
}

/// @brief 将线程挂载到指定链表中
/// @param hander 线程句柄
/// @param dst_list 目标链表
/// @return 1 成功 0 失败
tiny_int32_t tiny_suspend_thread_in_dst_list(tiny_thread_hander hander, tiny_list_t *dst_list)
{
	if (!hander || !dst_list)
	{
		return 0;
	}

	tiny_thread_t *tthread = hander;
	if (tthread->statu != THREAD_SUSPEND && tthread->statu != THREAD_DEAD)
	{
		if (tthread->statu == THREAD_BLOCKED)
		{
			tiny_timer_stop(&tthread->timer);
		}
		else
		{
			tiny_remove_node_from_list(&tthread->list_node_link);
		}
		tthread->statu = THREAD_SUSPEND;
		tiny_list_insert_pre(dst_list, &tthread->list_node_link);
		return 1;
	}
	return 0;
}

/// @brief 挂起线程
/// @param hander 线程句柄
void tiny_suspend_thread(tiny_thread_hander hander)
{
	if (!hander)
	{
		return;
	}

	int flag = disable_interrupt();
	int ret = tiny_suspend_thread_in_dst_list(hander, &thread_suspend_list);
	enable_interrupt(flag);
	if (ret == 1)
	{
		schedule();
	}
}

/// @brief 恢复挂起的线程
/// @param hander 线程句柄
void tiny_resume_thread(tiny_thread_hander hander)
{
	if (!hander)
	{
		return;
	}

	tiny_thread_t *tthread = hander;
	if (tthread->statu != THREAD_SUSPEND)
	{
		return;
	}
	int flag = disable_interrupt();
	tthread->statu = THREAD_READY;
	tiny_remove_node_from_list(&tthread->list_node_link);
	tiny_list_insert_pre(&thread_ready_list[tthread->cur_priority], &tthread->list_node_link);
	enable_interrupt(flag);
	schedule();
}

/// @brief 杀死线程
/// @param hander 线程句柄
void tiny_kill_thread(tiny_thread_hander hander)
{
	if (!hander)
	{
		return;
	}

	tiny_thread_t *tthread = hander;
	int flag = disable_interrupt();
	tiny_timer_stop(&tthread->timer);
	tiny_remove_node_from_list(&tthread->list_node_link);
	tthread->statu = THREAD_DEAD;
	tiny_list_insert_pre(&thread_exit_list, &tthread->list_node_link);
	
	if (hander == get_self_thread())
		schedule();
	
	enable_interrupt(flag);
	
	
}

/// @brief 线程自杀
/// @param  无需
void tiny_thread_kill_self(void)
{
	tiny_kill_thread(get_self_thread());
}

/// @brief 按tick数延时
/// @param tick 延时的tick数
void tiny_thread_delay_tick(tiny_int32_t tick)
{
	if (!tiny_get_schedule())
		return;
	
	if (cur_running_thread->statu != THREAD_RUNNING || tick == 0)
	{
		return;
	}
	if (tick < 0)
	{
		tiny_suspend_thread(cur_running_thread);
	}
	else
	{
		int flag = disable_interrupt();
		cur_running_thread->statu = THREAD_BLOCKED;
		cur_running_thread->timer_ret = THREAD_BLOCK_NOT_TIMEOUT;
		tiny_remove_node_from_list(&cur_running_thread->list_node_link);

		tiny_timer_set_interval(&cur_running_thread->timer, (tiny_uint32_t)tick);
		tiny_timer_start(&cur_running_thread->timer);

		schedule();
		enable_interrupt(flag);
	}
}

/// @brief 按毫秒数延时
/// @param ms 延时的毫秒数
void tiny_thread_delay_ms(tiny_int32_t ms)
{
	tiny_thread_delay_tick(CONVERT_MS_TO_TICK(ms));
}

/// @brief 获取当前线程句柄
/// @param  无需
/// @return 当前线程句柄
tiny_thread_hander get_self_thread(void)
{
	return (tiny_thread_hander)cur_running_thread;
}

#if IS_OPEN_GET_CPU == PROFILE_OPEN
/// @brief 获得线程runtime
/// @return runtime
tiny_uint64_t tiny_thread_get_thread_run_time(tiny_thread_hander thread)
{
	if (!thread)
	{
		return 0;
	}
	tiny_thread_t *tthread = thread;
	return tthread->run_time;
}

/// @brief 清除thread run_time
void tiny_thread_clear_thread_run_time(tiny_thread_hander thread)
{
	if (!thread)
	{
		return;
	}
	int flag = disable_interrupt();
	tiny_thread_t *tthread = thread;
	tthread->run_time = 0;
	enable_interrupt(flag);
}

/// @brief 获得all_runtime
/// @return all_runtime
tiny_uint64_t tiny_thread_get_all_thread_run_time(void)
{
	return all_runtime;
}

/// @brief 清除all_runtime
void tiny_thread_clear_all_thread_run_time(void)
{
	int flag = disable_interrupt();
	all_runtime = 0.0f;
	enable_interrupt(flag);
}

/// @brief 获得当前线程cpu占用率, 需要将IS_OPEN_GET_CPU置PROFILE_OPEN
/// @param thread 线程句柄
/// @return 当前cpu占用率
float tiny_thread_get_cpu_usage(tiny_thread_hander thread)
{
	if (!thread)
	{
		return 0;
	}
	tiny_thread_t *tthread = thread;
	return tthread->cpu_usage;
}

#endif

#if IS_OPEN_STACK_HIGH_WATER == PROFILE_OPEN
/// @brief 获得历史最低水位栈大小, 需要将IS_OPEN_STACK_HIGH_WATER置PROFILE_OPEN
/// @param thread 线程句柄
/// @return 历史最低水位栈大小
tiny_uint32_t tiny_thread_get_stack_high_water(tiny_thread_hander thread)
{
	tiny_uint32_t size = 0;
	if (!thread)
	{
		return 0;
	}
	tiny_thread_t *tthread = thread;
	for(; size < tthread->statck_size && (STACK_HIGH_WATER_FILL == tthread->stack[size]); ++size)
	{ }
	return size;
}
#endif

/// @brief 获得当前统计的最小剩余栈大小
/// @param thread 线程句柄
/// @return 当前统计的最小剩余栈大小，注意并不是实时的，是估计，例如printf打印浮点数内部需要100多字节栈空间无法统计到
tiny_uint32_t tiny_thread_get_min_remaining_stack(tiny_thread_hander thread)
{
	if (!thread)
	{
		return 0;
	}
	tiny_thread_t *tthread = thread;
	if ((tiny_uint32_t)tthread->sp  > (tiny_uint32_t)tthread->stack)
	{
		int flag = disable_interrupt();
		tthread->min_remain_stack = tthread->min_remain_stack > ((tiny_uint32_t)tthread->sp - (tiny_uint32_t)tthread->stack) ? ((tiny_uint32_t)tthread->sp - (tiny_uint32_t)tthread->stack) :
		tthread->min_remain_stack;
		enable_interrupt(flag);
	}
	else
	{
		return 0;
	}
	return tthread->min_remain_stack;
}

/// @brief 唤醒链表中的一个线程
/// @param list 线程链表
/// @param is_shedule 是否调度
tiny_thread_hander tiny_wakeap_one_list_thread(tiny_list_t *list, tiny_ret_status_t is_shedule)
{
	if (list->head)
	{
		tiny_thread_t *thread = TINY_THREAD_ENTRY(list->head);
		tiny_timer_stop(&thread->timer);
		tiny_remove_node_from_list(list->head);
		tiny_thread_startup(thread);
		if (is_shedule == tiny_true)
		{
			schedule();
		}
		return thread;
	}
	return tiny_null;
}

/// @brief 唤醒链表中的所有线程
/// @param list 线程链表
void tiny_wakeup_all_list_thread(tiny_list_t *list)
{
	if (!list)
	{
		return;
	}

	tiny_list_node_t *node = list->head;
	if (node)
	{
		int flag = disable_interrupt();
		do
		{
			tiny_thread_t *thread = TINY_THREAD_ENTRY(node);
			tiny_timer_stop(&thread->timer);
			tiny_thread_startup(thread);
			node = node->next;
		} while (node != list->head);
		list->head = tiny_null;
		enable_interrupt(flag);
	}
}

/// @brief 设置当前线程的优先级
/// @param thread 线程句柄
/// @param priority 优先级
void tiny_thread_set_cur_priority(tiny_thread_hander thread, tiny_uint32_t priority)
{
	if (!thread)
	{
		return;
	}

	tiny_thread_t *tthread = thread;
	if (tthread->cur_priority != priority)
	{
		int flag = disable_interrupt();
		if (tthread->statu == THREAD_READY)
		{
			tiny_remove_node_from_list(&tthread->list_node_link);
			tiny_list_insert_pre(&thread_ready_list[priority], &tthread->list_node_link);
		}
		tthread->cur_priority = priority;

		enable_interrupt(flag);
	}
}

/// @brief 恢复线程的初始优先级
/// @param thread 线程句柄
void tiny_thread_resume_init_priority(tiny_thread_hander thread)
{
	if (!thread)
	{
		return;
	}

	tiny_thread_t *tthread = thread;
	if (tthread->cur_priority != tthread->init_priority)
	{
		tiny_thread_set_cur_priority(thread, tthread->init_priority);
	}
}

/// @brief 线程礼让
/// @param  无需
void tiny_yield(void)
{
	tiny_thread_t *tthread = get_self_thread();
	if (tthread->statu == THREAD_RUNNING)
	{
		int flag = disable_interrupt();
		if (thread_ready_list[tthread->cur_priority].len > 1)
		{
			tiny_remove_node_from_list(&tthread->list_node_link);
			tiny_list_insert_pre(&thread_ready_list[tthread->cur_priority], &tthread->list_node_link);
		}
		schedule();
		enable_interrupt(flag);
	}
}

/// @brief 设置线程退出钩子
/// @param  thread 线程句柄
/// @param  exit_callback 回调函数
/// @param  param 回调参数
void tiny_thread_set_exit_hook(tiny_thread_hander thread, thread_callback_t exit_callback, void *param)
{
	tiny_thread_t *tthread = thread;
	if (tthread->statu != THREAD_DEAD && exit_callback)
	{
		tthread->exit_hook = exit_callback;
		tthread->exit_hook_param = param;
	}
}

/// @brief 遍历所有线程
/// @param  callback 回调函数
void tiny_list_thread(void (*callback)(tiny_thread_t *))
{
	if (thread_all_list.len > 0)
	{
		tiny_list_node_t* node = thread_all_list.head;
		do
		{
			tiny_thread_t *thread =STRUCT_TRANCING_PARENT(node, tiny_thread_t, list_all_thread_link);
			callback(thread);
			node = node->next;
		} while (thread_all_list.head != node);
	}
}

/// @brief 得到线程
/// @param  tid 线程id
/// @return tiny_thread_t* 线程实例
tiny_thread_t* tiny_get_thread_by_tid(tiny_uint32_t tid)
{
	if (thread_all_list.len > 0)
	{
		tiny_list_node_t* node = thread_all_list.head;
		do
		{
			tiny_thread_t *thread =STRUCT_TRANCING_PARENT(node, tiny_thread_t, list_all_thread_link);
			if (tid == thread->tid)
			{
				return thread;
			}
			node = node->next;
		} while (thread_all_list.head != node);
	}
	return tiny_null;
}

